/*
二维RGB(24bit)图像缩放

输入：
	源image像素矩阵(
		图像的左上角为原点 [0,0] 向右为x+，向下为y+, 每三个连续Byte表示一个像素的RGB值
		x主序，从头开始依次存储的像素点值如下所示，[x=0,y=0], [x=1,y=0],[x=2,y=0],......[x=Swidth-1, y=0],[x=1,y=1],[x=2,y=1],......)
	Swidth sheight
	目标image矩阵空间
	Twidth theight

图像缩放逻辑：
foreach 对目标image的每一个像素点timg
{
	计算四个顶点投影到源image的坐标位置（lu，ru，lb，rb）
	foreach 源image,X坐标在[lu.x, ru.x]并且Y坐标在[lu.y, rb.y]的每个像素simg
	{
		计算该在源image上的像素在目标image上投影的面积，占目标像素的面积比值 K(0.0f, 1.0f]
		timg.rgb+=  K * simg.rgb
	}//处理完源image像素集合，得到目标像素rgb值
}//完成计算目标image的每一个像素点的值

*/

#include <cmath>
#include <iostream>
#include <string> 
#include "FreeImage.h"
#include <sys/time.h>
#include <pthread.h>

using namespace std;
const static bool writeDebug = false;

class zoomError{
public:
	zoomError(string theerrmsg)
	{
		this->errMsg = theerrmsg;
	}
	zoomError(const char* theerrmsg)
	{
		this->errMsg = theerrmsg;
	}
	string errMsg;
};


float getRatio(const unsigned int slen, const unsigned int tlen, const unsigned int sv, const unsigned int tv) throw(zoomError)
{
	if(slen == tlen)
	{
		// y方向不变 s == t
		return 1.0f;
	}
	
	float inratio = 0.0f;
	const float stradtio = float(slen)/float(tlen);

	if(stradtio<1.0f)
	{
		// t > s, 源像素投影在目标图像上源像素框比目标像素框较大
		if((float)sv <= float(tv)*stradtio)
		{
			// 源像素上边缘 比 目标像素上边缘 小
			if((float)(sv+1) < float(tv)*stradtio)
			{
				// 源像素下边缘在目标像素上边缘以上
				zoomError errobj("t>s, sv<tv, but find (sv+1)<tv");
				throw errobj;
			}
			else
			{
				if((float)(sv+1) < float(tv+1)*stradtio)
				{
					// 源像素下边缘在目标像素上下边缘之间
					inratio = float(sv+1)/stradtio - tv;
				}
				else
				{
					// 源像素下边缘在目标像素下边缘以下
					inratio = 1.0f;
				}
			}
		}
		else if((float)sv <= float(tv+1)*stradtio)
		{
			// 源像素上边缘在目标像素上下边缘之间
			if((float)(sv+1) < float(tv+1)*stradtio)
			{
				// 源像素下边缘在目标像素下边缘以上
				zoomError errobj("t>s, sv<(tv+1), but find (sv+1)<(tv+1)");
				throw errobj;
			}
			else
			{
				// 源像素下边缘在目标像素下边缘以下
				inratio = float(tv+1)-(float(sv)/stradtio);
			}
		}
		else
		{
			// 源像素上边缘在目标像素下边缘以下
			zoomError errobj("t>s, sv>tv, but find sv>(tv+1)");
			throw errobj;
		}
	}
	else
	{
		// y方向缩小，t < s, 源像素投影在目标图像上源像素框比目标像素框较小
		if((float)sv <= float(tv)*stradtio)
		{
			// 源像素上边缘在目标像素上边缘以上
			if((float)(sv+1) < float(tv)*stradtio)
			{
				// 源像素下边缘在目标像素上边缘以上
				zoomError errobj("t<s, sv<tv, but find (sv+1)<tv");
				throw errobj;
			}
			else
			{
				if((float)(sv+1) < float(tv+1)*stradtio)
				{
					// 源像素下边缘在目标像素下边缘以上
					inratio = float(sv+1)-((float)(tv)*stradtio);//sw * ((sx+1/sw) - (tx/tw)) 
				}
				else
				{
					// 源像素下边缘在目标像素下边缘以下
					zoomError errobj("t<s, sv<tv, buf find (sv+1)>(tv+1)");
					throw errobj;
				}
			}
		}
		else if((float)sv <= float(tv+1)*stradtio)
		{
			// 源像素上边缘在目标像素下边缘以上
			if((float)(sv+1) < float(tv+1)*stradtio)
			{
				// 源像素下边缘在目标像素下边缘以上
				inratio = 1.0f;
			}
			else
			{
				// 源像素下边缘在目标像素下边缘以下
				inratio = ((float)(tv+1)*stradtio) - (float)sv; //sw * (tx+1/tw - sx/sw)
			}
		}
		else
		{
			// 源像素上边缘在目标像素下边缘以下
			zoomError errobj("t<s, sv>tv, but find sv>(tv+1)");
			throw errobj;
		}

		inratio /= stradtio;
	}
	return inratio;
}

int imageZoom(
	const unsigned int pixbytes,			// image每个像素用多少字节表示，
	const unsigned char* const srcImage,	// 源image像素起始地址
	const unsigned int swidth,				// 源image宽度
	const unsigned int sheight,				// 源image高度
	unsigned char* const targetImage,		// 目标image像素起始地址
	const unsigned int twidth,				// 目标image宽度
	const unsigned int theight				// 目标image高度
) throw(zoomError) 
{
	if(0==pixbytes)
	{
		zoomError errobj("in func imageZoom, find pixbytes==0");
		throw errobj;
	}
	if(0 == swidth || 0 == sheight)
	{
		zoomError errobj("in func imageZoom, find 0 == swidth || 0 == sheight");
		throw errobj;
	}
	if(0 == twidth || 0 == theight)
	{
		zoomError errobj("in func imageZoom, find 0 == twidth || 0 == theight");
		throw errobj;
	}
	if(NULL == srcImage || NULL == targetImage)
	{
		zoomError errobj("in func imageZoom, find NULL == srcImage || NULL == targetImage");
		throw errobj;
	}
	unsigned char* trgbpos = targetImage;
	//const float tswradtio = float(twidth)/float(swidth);	// 目标image和源image 的宽度比
	//const float tshradtio = float(theight)/float(sheight);	// 目标image和源image 的高度比

	const float stwradtio = float(swidth)/float(twidth);	// 源image和目标image 的宽度比
	const float sthradtio = float(sheight)/float(theight);	// 源image和目标image 的高度比

	float sumv[pixbytes];
	unsigned int sxfrom, sxto, syfrom, syto;
	const unsigned char* srgbpos;
	float ratiosum, sxinratio, syinratio, rgbratio;

	for(unsigned int ty=0; ty<theight; ++ty)
	{
		for(unsigned int tx=0; tx<twidth; ++tx)
		{
			//foreach 对目标image的每一个像素点timg
			
			//计算四个顶点投影到源image的坐标位置（lu，ru，lb，rb）
			sxfrom = (unsigned int)(float(tx)*stwradtio); 
			sxfrom = sxfrom>=swidth ? swidth-1 : sxfrom;

			sxto = (unsigned int)(float(tx+1)*stwradtio); 
			sxto = sxto>=swidth ? swidth-1 : sxto;

			syfrom = (unsigned int)(float(ty)*sthradtio); 
			syfrom = syfrom>=sheight ? sheight-1 : syfrom;

			syto = (unsigned int)(float(ty+1)*sthradtio); 
			syto = syto>=sheight ? sheight-1 : syto;

			ratiosum = 0.0f;
			sxinratio = 0.0f;
			syinratio = 0.0f;
			rgbratio = 0.0f;

			for(unsigned int i=0;i<pixbytes;++i)
			{
				sumv[i] = 0.0f;
			}
			
			unsigned int sy=0;
			unsigned int sx=0;
			try
			{
				for(sy=syfrom; sy<=syto; ++sy)
				{
					syinratio = getRatio(sheight, theight, sy, ty);
					for(sx=sxfrom; sx<=sxto; ++sx)
					{
						//foreach 源image,X坐标在[lu.x, ru.x]并且Y坐标在[lu.y, rb.y]的每个像素simg

						// 计算该在源image上的像素在目标image上投影的面积，占目标像素的面积比值 K(0.0f, 1.0f]
						// 源像素投影在目标像素上
						sxinratio  = getRatio(swidth, twidth, sx, tx);
						rgbratio = sxinratio*syinratio;
						ratiosum += rgbratio;

						srgbpos = srcImage;
						srgbpos += ((sy*swidth+sx)*pixbytes);
						if(writeDebug)
						{
							cout<<"tx="<<tx<<",\tty="<<ty<<",\tsx="<<sx<<",\tsy="<<sy<<",\trgb=(";
						}
						for(unsigned int i=0;i<pixbytes;++i)
						{
							sumv[i] += rgbratio*(float)srgbpos[i];
							if(writeDebug)
							{
								cout<<(int)srgbpos[i]<<",";
							}
						}
						if(writeDebug)
						{
							cout<<"),\tsxr="<<sxinratio<<",\tsyr="<<syinratio<<",\trgbr="<<rgbratio<<endl;
						}
					}
				}
			}
			catch(zoomError errobj)
			{
				cout<<endl<<"catch zoomError in function imageZoom:"<<endl;
				cout<<"\ttx="<<tx<<",\tty="<<ty<<",\tsx="<<sx<<",\tsy="<<sy<<endl;
				cout<<"\terrobj.errMsg="<<errobj.errMsg<<endl;
				throw errobj;
			}

			if(writeDebug)
			{
				cout<<"tx="<<tx<<",\tty="<<ty<<",\trgb=(";
			}
			for(unsigned int i=0;i<pixbytes;++i)
			{
				trgbpos[i] = (char)round(sumv[i]);
				if(writeDebug)
				{
					cout<<(int)trgbpos[i]<<",";
				}
			}
			if(writeDebug)
			{
				cout<<"),\tratiosum="<<ratiosum<<endl<<endl;
			}
			trgbpos += pixbytes;
		}
	}
	return 1;
}

struct ctinfo
{
	unsigned int pixbytes;			// image每个像素用多少字节表示，
	const unsigned char* srcImage;	// 源image像素起始地址
	unsigned int swidth;				// 源image宽度
	unsigned int sheight;				// 源image高度
	unsigned char* targetImage;		// 目标image像素起始地址
	unsigned int twidth;				// 目标image宽度
	unsigned int theight;				// 目标image高度
	unsigned int numThread;			// cpu nums
	unsigned int threadidx;			// 处理线程编号
};

void* zoomTread(void* zomminfo)
{
	if(NULL == zomminfo)
	{
		return NULL;
	}
	struct ctinfo* thezoominfo = (struct ctinfo*)zomminfo;
	
	const unsigned int pixbytes			= thezoominfo->pixbytes;
	const unsigned char* const srcImage = thezoominfo->srcImage;
	const unsigned int swidth			= thezoominfo->swidth;
	const unsigned int sheight			= thezoominfo->sheight;
	unsigned char* const targetImage	= thezoominfo->targetImage;
	const unsigned int twidth			= thezoominfo->twidth;
	const unsigned int theight			= thezoominfo->theight;
	const unsigned int numThread		= thezoominfo->numThread;
	const unsigned int threadidx		= thezoominfo->threadidx;

	const unsigned int rowperthread = (theight/numThread)+1;
	const unsigned int tyfrom = threadidx*rowperthread;
	const unsigned int tyto = (tyfrom+rowperthread) > theight ? theight : (tyfrom+rowperthread);
	cout<<"in zoomTread, threadidx="<<threadidx<<", tyfrom="<<tyfrom<<", tyto="<<tyto<<endl;
	
	unsigned char* trgbpos = targetImage;
	//const float tswradtio = float(twidth)/float(swidth);	// 目标image和源image 的宽度比
	//const float tshradtio = float(theight)/float(sheight);	// 目标image和源image 的高度比

	const float stwradtio = float(swidth)/float(twidth);	// 源image和目标image 的宽度比
	const float sthradtio = float(sheight)/float(theight);	// 源image和目标image 的高度比

	float sumv[pixbytes];
	unsigned int sxfrom, sxto, syfrom, syto;
	const unsigned char* srgbpos;
	float ratiosum, sxinratio, syinratio, rgbratio;

	
	for(unsigned int ty=tyfrom; ty<tyto; ++ty)
	{
		for(unsigned int tx=0; tx<twidth; ++tx)
		{
			//foreach 对目标image的每一个像素点timg
			
			//计算四个顶点投影到源image的坐标位置（lu，ru，lb，rb）
			sxfrom = (unsigned int)(float(tx)*stwradtio); 
			sxfrom = sxfrom>=swidth ? swidth-1 : sxfrom;

			sxto = (unsigned int)(float(tx+1)*stwradtio); 
			sxto = sxto>=swidth ? swidth-1 : sxto;

			syfrom = (unsigned int)(float(ty)*sthradtio); 
			syfrom = syfrom>=sheight ? sheight-1 : syfrom;

			syto = (unsigned int)(float(ty+1)*sthradtio); 
			syto = syto>=sheight ? sheight-1 : syto;

			ratiosum = 0.0f;
			sxinratio = 0.0f;
			syinratio = 0.0f;
			rgbratio = 0.0f;

			for(unsigned int i=0;i<pixbytes;++i)
			{
				sumv[i] = 0.0f;
			}
			
			unsigned int sy=0;
			unsigned int sx=0;
			try
			{
				for(sy=syfrom; sy<=syto; ++sy)
				{
					syinratio = getRatio(sheight, theight, sy, ty);
					for(sx=sxfrom; sx<=sxto; ++sx)
					{
						//foreach 源image,X坐标在[lu.x, ru.x]并且Y坐标在[lu.y, rb.y]的每个像素simg

						// 计算该在源image上的像素在目标image上投影的面积，占目标像素的面积比值 K(0.0f, 1.0f]
						// 源像素投影在目标像素上
						sxinratio  = getRatio(swidth, twidth, sx, tx);
						rgbratio = sxinratio*syinratio;
						ratiosum += rgbratio;

						srgbpos = srcImage;
						srgbpos += ((sy*swidth+sx)*pixbytes);
						if(writeDebug)
						{
							cout<<"tx="<<tx<<",\tty="<<ty<<",\tsx="<<sx<<",\tsy="<<sy<<",\trgb=(";
						}
						for(unsigned int i=0;i<pixbytes;++i)
						{
							sumv[i] += rgbratio*(float)srgbpos[i];
							if(writeDebug)
							{
								cout<<(int)srgbpos[i]<<",";
							}
						}
						if(writeDebug)
						{
							cout<<"),\tsxr="<<sxinratio<<",\tsyr="<<syinratio<<",\trgbr="<<rgbratio<<endl;
						}
					}
				}
			}
			catch(zoomError errobj)
			{
				cout<<endl<<"catch zoomError in function imageZoom:"<<endl;
				cout<<"\ttx="<<tx<<",\tty="<<ty<<",\tsx="<<sx<<",\tsy="<<sy<<endl;
				cout<<"\terrobj.errMsg="<<errobj.errMsg<<endl;
				throw errobj;
			}

			if(writeDebug)
			{
				cout<<"tx="<<tx<<",\tty="<<ty<<",\trgb=(";
			}
			for(unsigned int i=0;i<pixbytes;++i)
			{
				trgbpos[i] = (char)round(sumv[i]);
				if(writeDebug)
				{
					cout<<(int)trgbpos[i]<<",";
				}
			}
			if(writeDebug)
			{
				cout<<"),\tratiosum="<<ratiosum<<endl<<endl;
			}
			trgbpos += pixbytes;
		}
	}

	return zomminfo;
}

int imageZoomMT(
	const unsigned int pixbytes,			// image每个像素用多少字节表示，
	const unsigned char* const srcImage,	// 源image像素起始地址
	const unsigned int swidth,				// 源image宽度
	const unsigned int sheight,				// 源image高度
	unsigned char* const targetImage,		// 目标image像素起始地址
	const unsigned int twidth,				// 目标image宽度
	const unsigned int theight				// 目标image高度
) 
{
	if(0==pixbytes)
	{
		zoomError errobj("in func imageZoom, find pixbytes==0");
		throw errobj;
	}
	if(0 == swidth || 0 == sheight)
	{
		zoomError errobj("in func imageZoom, find 0 == swidth || 0 == sheight");
		throw errobj;
	}
	if(0 == twidth || 0 == theight)
	{
		zoomError errobj("in func imageZoom, find 0 == twidth || 0 == theight");
		throw errobj;
	}
	if(NULL == srcImage || NULL == targetImage)
	{
		zoomError errobj("in func imageZoom, find NULL == srcImage || NULL == targetImage");
		throw errobj;
	}
	
	unsigned int numThread = sysconf(_SC_NPROCESSORS_CONF);
	cout<<"in func imageZoomMT numThread = "<<numThread<<endl;

	pthread_t tidp[numThread];
	struct ctinfo cptinf[numThread];

	for(int i=0;i<numThread;++i)
	{
		cptinf[i].numThread = numThread;
		cptinf[i].threadidx = i;
		cptinf[i].pixbytes	= pixbytes;
		cptinf[i].srcImage	= srcImage;
		cptinf[i].swidth	= swidth;
		cptinf[i].sheight	= sheight;
		cptinf[i].targetImage= targetImage;
		cptinf[i].twidth	= twidth;
		cptinf[i].theight	= theight;

		//printf("in multiThread pthread_create %d %d %d\n", i, cptinf[i].offset, cptinf[i].cptnum);
		int error = pthread_create(&(tidp[i]),NULL, zoomTread, (void*)(&(cptinf[i])));
		if(0 != error)
		{
			cout<<"in multiThread fail to call pthread_create"<<endl;
			return 0;
		}
	}
	void* re;
	for(int i=0;i<numThread;++i)
	{
		//printf("in multiThread pthread_join %d\n", i);
		pthread_join(tidp[i], &re);
	}

	return 1;
}


int showImagePix(const unsigned char * const simage, unsigned int sw, unsigned int sh, unsigned int pixlen)
{
	cout<<endl<<"in func showImagePix"<<endl;
	int loop=0;
	for(unsigned int i=0;i<sh;++i)
	{
		for(unsigned int j=0;j<sw;++j)
		{
			cout<<"["<<j<<","<<i<<"](";
			for(unsigned int k=0;k<pixlen;++k)
			{
				cout<<(int)simage[loop]<<",";
				++loop;
			}
			cout<<")\t";
		}
		cout<<endl;
	}

	return 0;
}

int selftest()
{
	const unsigned int pixlen = 3;
	//*
	const unsigned int sw = 1024;
	const unsigned int sh = 1024;
	const unsigned int tw = 320;
	const unsigned int th = 320;
	//*/

	/*
	const unsigned int sw = 5;
	const unsigned int sh = 5;
	const unsigned int tw = 16;
	const unsigned int th = 16;
	//*/

	unsigned char* simage = new unsigned char[sw*sh*pixlen];
	unsigned int loop=0;
	for(unsigned int i=0;i<sh;++i)
	{
		for(unsigned int j=0;j<sw;++j)
		{
			for(unsigned int k=0;k<pixlen;++k)
			{
				simage[loop] = char((i*j+loop)%256);
				++loop;
			}
		}
	}
	unsigned char* timage = new unsigned char[tw*th*pixlen];
	try
	{
		imageZoom(pixlen, simage, sw, sh, timage, tw, th);
		//imageZoom(pixlen, timage, tw, th, simage, sw, sh);
	}
	catch(zoomError errobj)
	{
		cout<<endl<<"EXCEPTIONG HAPPENED in main"<<endl;
		return 0;
	}
	//showImagePix(timage, tw, th, pixlen);
	//showImagePix(simage, sw, sh, pixlen);

	return 0;
}

//g++ -lfreeimage -lpthread -O3 -o imageZoomTest imageZoomTest.cpp
int main()
{
	/*
	const char* srcImagePath="/home/mengchang/IMGP5870.JPG";
	const char* targetImagePath="/home/mengchang/test1_cpu.bmp";
	const char* targetImagePathFI="/home/mengchang/test1_fi.bmp";

	const char* srcImagePath="/home/mengchang/Avatar_002009.jpg";
	const char* targetImagePath="/home/mengchang/test2_cpu.bmp";
	const char* targetImagePathFI="/home/mengchang/test2_fi.bmp";

	const char* srcImagePath="/home/mengchang/acmod.jpg";
	const char* targetImagePath="/home/mengchang/test3_cpu.bmp";
	const char* targetImagePathFI="/home/mengchang/test3_fi.bmp";
	*/
	
	const char* srcImagePath="/home/mengchang/test3.JPG";
	const char* targetImagePath="/home/mengchang/test4_cpu.bmp";
	const char* targetImagePathFI="/home/mengchang/test4_fi.bmp";

	FIBITMAP * dib = FreeImage_Load(FIF_JPEG, srcImagePath, BMP_DEFAULT);

	if(NULL == dib)
	{
		cout<<"fail to read image "<<srcImagePath<<endl;
		return 0;
	}
	const unsigned int bitsPerPix = FreeImage_GetBPP(dib);
	const unsigned int inImageWidth = FreeImage_GetWidth(dib);
	const unsigned int inImageHeight = FreeImage_GetHeight(dib);
	const unsigned int inImagePitch = FreeImage_GetPitch(dib);
	FREE_IMAGE_TYPE inImageType = FreeImage_GetImageType(dib);
	FREE_IMAGE_COLOR_TYPE inImageColorType = FreeImage_GetColorType(dib);

	cout<<"inImageType="<<inImageType
		<<",\tbitsPerPix="<<bitsPerPix
		<<",\tinImageWidth="<<inImageWidth
		<<",\tinImageHeight="<<inImageHeight
		<<",\tinImagePitch="<<inImagePitch
		<<",\tinImageColorType="<<inImageColorType
		<<",\tsizeof(BYTE)="<<sizeof(BYTE)
		<<endl;
	BYTE *srcbits = (BYTE*)FreeImage_GetBits(dib);

	const unsigned int pixlen = bitsPerPix/8;
	const unsigned int tw = 1024;
	const unsigned int th = 1024;
	FIBITMAP * outImageBmp = FreeImage_AllocateT(FIT_BITMAP, tw, th, 24);
	if(NULL == outImageBmp)
	{
		cout<<"fail to call FreeImage_AllocateT"<<endl;
		return 0;
	}
	cout<<"outimage, Pitch="<<FreeImage_GetPitch(outImageBmp)<<",\tpixlen="<<pixlen<<endl;
	BYTE *outbits = (BYTE*)FreeImage_GetBits(outImageBmp);
	if(NULL == outbits)
	{
		cout<<"fail to get ptr outbits"<<endl;
		return 0;
	}

	timeval clkBegin, clkEnd;
	gettimeofday(&clkBegin, NULL);
	//unsigned char* timage = new unsigned char[tw*th*pixlen];
	try
	{
		//imageZoom(pixlen, (const unsigned char* const)srcbits, inImageWidth, inImageHeight, (unsigned char*)outbits, tw, th);
		//imageZoom(pixlen, timage, tw, th, simage, sw, sh);
		imageZoomMT(pixlen, (const unsigned char* const)srcbits, inImageWidth, inImageHeight, (unsigned char*)outbits, tw, th);
	}
	catch(zoomError errobj)
	{
		cout<<endl<<"EXCEPTIONG HAPPENED in main"<<endl;
		return 0;
	}
	gettimeofday(&clkEnd, NULL);
	long timeZoom = (clkEnd.tv_usec - clkBegin.tv_usec);
	timeZoom += 1000000L*(clkEnd.tv_sec - clkBegin.tv_sec);
	cout<<"timeZoom = "<<timeZoom<<"us = "<<(timeZoom/1000L)<<"ms"<<endl;

	//showImagePix((unsigned char*)outbits, tw, th, 3);

	if (FreeImage_Save(FIF_BMP, outImageBmp, targetImagePath, BMP_DEFAULT))
	{
		// bitmap successfully saved!
		cout<<"succ to write image file "<<targetImagePath<<endl;
	}
	else
	{
		cout<<"fail to write image file "<<targetImagePath<<endl;
	}

	gettimeofday(&clkBegin, NULL);
	FIBITMAP * firsBmp = FreeImage_Rescale(dib, tw, th, FILTER_BOX); 
	gettimeofday(&clkEnd, NULL);
	long timeZoomfi = (clkEnd.tv_usec - clkBegin.tv_usec);
	timeZoomfi += 1000000L*(clkEnd.tv_sec - clkBegin.tv_sec);
	cout<<"ttimeZoomfi = "<<timeZoomfi<<"us = "<<(timeZoomfi/1000L)<<"ms"<<endl;

	if (FreeImage_Save(FIF_BMP, firsBmp, targetImagePathFI, BMP_DEFAULT))
	{
		// bitmap successfully saved!
		cout<<"succ to write image file "<<targetImagePathFI<<endl;
	}
	else
	{
		cout<<"fail to write image file "<<targetImagePathFI<<endl;
	}

	FreeImage_Unload(dib);
	FreeImage_Unload(outImageBmp);
	return 0;
}
